# coding=utf-8
"""
author: jamon
"""
import asyncio
from typing import Optional, Any, List, Awaitable, TypeVar

from client.net.socket_service import WebSocketService, ConnectStatus
from obespoir.share.singleton import Singleton
from obespoir.share.espoir_log import global_log as logger
from package.universe import EsException

from client.net.message_handler import handle_message


_T = TypeVar('_T')


async def send_msg_serialize_async(coro_or_future_list: List[Awaitable[_T]]):
    for coro in coro_or_future_list:
          await coro


def send_msg_serialize(coro_or_future_list: List[Awaitable[_T]]):
    return asyncio.ensure_future(send_msg_serialize_async(coro_or_future_list))


class NetConnectManager(object, metaclass=Singleton):

    def __init__(self):
        self.ws_conn: Optional[WebSocketService] = None

    def init_connect(self, host: str, port: int):
        if not self.ws_conn:
            self.ws_conn = WebSocketService(host, port, self)
            self.ws_conn.handle_message = handle_message

    def reset_ws_conn(self):
        self.ws_conn = None

    async def start(self, callback) -> None:
        if not self.ws_conn:
            raise EsException("ConnectionNeedInit")
        self.ws_conn.conn_callback = callback
        await self.ws_conn.run()

    async def wait_ready(self):
        while 1:
            if self.ws_conn and \
                    self.ws_conn.cur_status == ConnectStatus.CONNECTED:
                break
            await asyncio.sleep(0.1)
            logger.debug("wait connect ready")

    async def send_message(self, command_id: int, data: dict) -> Any:
        await self.wait_ready()
        result = await self.ws_conn.handle_send(command_id, data)
        logger.info("end", command_id=command_id, data=data, result=result)
        return result

    def send_msg(self, command_id: int, data: dict):
        asyncio.ensure_future(self.send_message(command_id, data))
